package com.deng.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.deng.entity.Post;
import com.deng.mapper.PostMapper;
import com.deng.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deng.util.RedisUtil;
import com.deng.vo.PostVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import java.util.Date;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author dengwenxiong
 * @since 2021-05-05
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {
    @Autowired
    PostMapper postMapper;
    @Autowired
    RedisUtil redisUtil;

    //分页
    @Override
    public IPage<PostVo> paging(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {
        //利用mybatis-plus的特性
        if(level == null) level = -1;

        QueryWrapper wrapper = new QueryWrapper<Post>()
                .eq(categoryId != null,  "category_id", categoryId)
                .eq(userId != null,  "user_id", userId)
                .eq(level == 0,  "level", 0)
                .gt(level > 0,  "level", 0)
                .orderByDesc(order != null, order);
        return postMapper.selectPosts(page,wrapper);
    }

    @Override
    public PostVo selectOnePost(QueryWrapper<Post> wrapper) {

        return postMapper.selectOnePost(wrapper);
    }
    //本周热议
    @Override
    public void initWeekRank() {
        //获取七天内的文章
        List<Post> posts=this.list(new QueryWrapper<Post>().ge("created", DateUtil.offsetDay(new Date(),-7)).select("id, title, user_id, comment_count, view_count, created"));
        //初始化文章的评论量
        for(Post post:posts){
            //根据文章创建日期生成redis缓存中每一天的key
            String key="day:rank:"+DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);
            redisUtil.zSet(key,post.getId(),post.getCommentCount());
            //设置7天后自动过期
            long between=DateUtil.between(new Date(),post.getCreated(), DateUnit.DAY);
            long expireTime=(7-between)*24*60*60;//有效时间
            redisUtil.expire(key,expireTime);
            // 同时缓存文章的一些初始信息，标题，id，作者等等
            this.hashCachePostIdAndTitle(post,expireTime);
        }

        //将每天的评论量做并集
        this.zunionAdnStoreLast7DayWeekRank();

    }

    //合并文章本周评论数量
    private void zunionAdnStoreLast7DayWeekRank() {
        String todayKey="day:rank:"+DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);
        String key="week:rank";
        List<String> otherKeys=new ArrayList<>();
        for(int i=-6;i<0;i++){
            String temp="day:rank:"+DateUtil.format(DateUtil.offsetDay(new Date(),i), DatePattern.PURE_DATE_FORMAT);
            otherKeys.add(temp);
        }
        redisUtil.zUnionAndStore(todayKey,otherKeys,key);

    }

    private void hashCachePostIdAndTitle(Post post, long expireTime) {
        String key="rank:post:"+post.getId();
        if(!redisUtil.hasKey(key)){
            redisUtil.hset(key,"post:id",post.getId(),expireTime);
            redisUtil.hset(key,"post:title",post.getTitle(),expireTime);
            redisUtil.hset(key,"post:commentCount",post.getCommentCount(),expireTime);
            redisUtil.hset(key,"post:viewCount",post.getViewCount(),expireTime);
        }

    }
    @Override
    public void incrCommentCountAndUnionForWeekRank(long postId, boolean isIncr) {
        String currentKey="day:rank:"+DateUtil.format(new Date(),DatePattern.PURE_DATE_FORMAT);
        redisUtil.zIncrementScore(currentKey,postId,isIncr?1:-1);
        Post post = this.getById(postId);

        // 7天后自动过期(15号发表，7-（18-15）=4)
        long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
        long expireTime = (7 - between) * 24 * 60 * 60; // 有效时间

        // 缓存这篇文章的基本信息
        this.hashCachePostIdAndTitle(post, expireTime);
        //重新并集
        this.zunionAdnStoreLast7DayWeekRank();
    }

    @Override
    public void putViewCount(PostVo vo) {
        String key="rank:post:"+vo.getId();
        //从缓存获取viewcount,+1,如果缓存中没有就从实体获取并+1
        Integer viewCount=(Integer)redisUtil.hget(key,"post:viewCount");
        if(viewCount!=null){
            vo.setViewCount(viewCount+1);
        }else{
            vo.setViewCount(vo.getViewCount()+1);
        }
        //然后将值同步到缓存里
        redisUtil.hset(key,"post:viewCount",vo.getViewCount());
    }

}
